package com.globefrog.example.consumer;

import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.google.common.collect.Maps;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.core.constant.properties.ShardingPropertiesConstant;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @author : Globe-Frog
 * @date : Create in 2021/7/12
 */
@Configuration
@EnableAspectJAutoProxy
@MapperScan("com.globefrog.example.consumer.*.mapper")
@EnableTransactionManagement(proxyTargetClass = true)
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,
    DataSourceTransactionManagerAutoConfiguration.class})
public class MockDbConfig {

  public static final String CONSUMER_MASTER_DS = "consumer_master_ds";
  public static final String CONSUMER_SLAVE_DS = "consumer_slave_ds";

  @Bean
  @Primary
  public DataSource dataSource() throws SQLException {
    Map<String, DataSource> dataSourceMap = Maps.newHashMap();
    dataSourceMap.put(CONSUMER_MASTER_DS, dataSourceMaster());
    ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
    shardingRuleConfig.setDefaultDataSourceName(CONSUMER_MASTER_DS);
    return ShardingDataSourceFactory
        .createDataSource(dataSourceMap, shardingRuleConfig, shardProperties());
  }

  @Bean(name = CONSUMER_MASTER_DS)
  public DataSource dataSourceMaster() throws SQLException {
    return create(CONSUMER_MASTER_DS);
  }

  @Bean(name = CONSUMER_SLAVE_DS)
  public DataSource dataSource1() throws SQLException {
    return create(CONSUMER_SLAVE_DS);
  }

  private Properties shardProperties() {
    Properties properties = new Properties();
    properties.setProperty(ShardingPropertiesConstant.SQL_SHOW.getKey(), "true");
    return properties;
  }

  private DataSource create(String name) throws SQLException {
    return new EmbeddedDatabaseBuilder().setName(name)
        .setDataSourceFactory(new CustomDriverDataSourceFactory()).setType(EmbeddedDatabaseType.H2)
        .addScript("init.sql").build();
  }

  @Bean("sqlSessionFactory")
  @Primary
  public SqlSessionFactory sqlSessionFactory() throws Exception {
    MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
    sqlSessionFactoryBean.setDataSource(dataSource());
    return sqlSessionFactoryBean.getObject();
  }

  @Bean
  public PlatformTransactionManager transactionManager() throws SQLException {
    return new DataSourceTransactionManager(dataSource());
  }
}
